﻿using System;
using System.Web.Security;

using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlServer.Management.Common;
using System.Data.SqlClient;
using System.Configuration;
using Grishko.DataTier;


namespace Ecopsy.Providers
{
    public class XmlMembershipProvider : MembershipProvider
    {
        public string _Name;
        public string _ConnectionString;
        public string _UserChekRule;
        public string _ApplicationName;

        private string _FileName;
        

        private bool _EnablePasswordReset;
        private bool _RequiresQuestionAndAnswer;
        private string _PasswordStrengthRegEx;


        private int _MaxInvalidPasswordAttempts;
        private int _MinRequiredNonAlphanumericChars;
        private int _MinRequiredPasswordLength;
        private MembershipPasswordFormat _PasswordFormat;


        private string SQLServerName_;      // Имя сервера 
        private string DatabaseName_;       // Имя БД
        private string UserName_;           // имя пользователя
        private string Pwd_;                // пароль
        private string _DefaultSchema="dbo";// схема по умолчанию

        public string SQLServerName
        {
            get
            {
                return SQLServerName_  ;
            }
        }

        public string DatabaseName
        {
            get
            {
                return DatabaseName_;
            }
        }

        public string UserName
        {
            get
            {
                return UserName_;
            }
        }

        public string Pwd
        {
            get
            {
                return Pwd_;
            }
        }


                

        public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
        {
            
            if (config == null)
            {
                throw new ArgumentNullException("config");
            }
            if (string.IsNullOrEmpty(name))
            {
                name = "XmlMembershipProvider";
            }
            if (string.IsNullOrEmpty(config["description"]))
            {
                config.Remove("description");
                config.Add("description", "XML Membership Provider");
            }

            // Initialize the base class
            base.Initialize(name, config);

            // Initialize default values
            _ConnectionString = String.Empty;
            _ApplicationName = "DefaultApp";
            _EnablePasswordReset = false;
            _PasswordStrengthRegEx = @"[\w| !§$%&/()=\-?\*]*";
            _MaxInvalidPasswordAttempts = 3;
            _MinRequiredNonAlphanumericChars = 1;
            _MinRequiredPasswordLength = 5;
            _RequiresQuestionAndAnswer = false;
            //_PasswordFormat = MembershipPasswordFormat.Hashed;
            _PasswordFormat = MembershipPasswordFormat.Clear;



            
            // Now go through the properties and initialize custom values
            config = ConfigurationManager.AppSettings;
            foreach (string key in ConfigurationManager.AppSettings )
            {
                switch (key.ToLower())
                {
                    case "sqlservername":
                        SQLServerName_ = config[key];                        
                        break;
                    
                    case "username":
                        UserName_ = config[key];                        
                        break;

                    case "pwd":
                        Pwd_= config[key];                        
                        break;
                    
                    case "applicationname":
                        _ApplicationName = config[key];
                        _ApplicationName = ConfigurationSettings.AppSettings["applicationname"].ToString();
                        break;

                    case "databasename":                    
                        DatabaseName_ = ConfigurationSettings.AppSettings["databasename"].ToString () ;
                        
                        break;

                    case "defaultschema":                        
                        _DefaultSchema = ConfigurationSettings.AppSettings["defaultschema"].ToString();
                        break;                    

                    case "filename":
                        _FileName = config[key];
                        break;
                    case "enablepasswordreset":
                        _EnablePasswordReset = bool.Parse(config[key]);
                        break;
                    case "passwordstrengthregex":
                        _PasswordStrengthRegEx = config[key];
                        break;
                    case "maxinvalidpasswordattempts":
                        _MaxInvalidPasswordAttempts = int.Parse(config[key]);
                        break;
                    case "minrequirednonalphanumericchars":
                        _MinRequiredNonAlphanumericChars = int.Parse(config[key]);
                        break;
                    case "minrequiredpasswordlength":
                        _MinRequiredPasswordLength = int.Parse(config[key]);
                        break;
                    case "passwordformat":
                        _PasswordFormat = (MembershipPasswordFormat)Enum.Parse(
                                    typeof(MembershipPasswordFormat), config[key]);
                        break;
                    case "requiresquestionandanswer":
                        _RequiresQuestionAndAnswer = bool.Parse(config[key]);
                        break;
                }
            }

           

        }

        #region Properties

        public override string ApplicationName
        {
            get
            {
                return _ApplicationName;
            }
            set
            {
                _ApplicationName = value;
                
            }
        }

        public override bool EnablePasswordReset
        {
            get { return _EnablePasswordReset; }
        }

        public override bool EnablePasswordRetrieval
        {
            get
            {
                if (this.PasswordFormat == MembershipPasswordFormat.Hashed)
                    return false;
                else
                    return true;
            }
        }

        public override int MaxInvalidPasswordAttempts
        {
            get { return _MaxInvalidPasswordAttempts; }
        }

        public override int MinRequiredNonAlphanumericCharacters
        {
            get { return _MinRequiredNonAlphanumericChars; }
        }

        public override int MinRequiredPasswordLength
        {
            get { return _MinRequiredPasswordLength; }
        }

        public override int PasswordAttemptWindow
        {
            get { return 20; }
        }

        public override MembershipPasswordFormat PasswordFormat
        {
            get { return _PasswordFormat; }
        }

        public override string PasswordStrengthRegularExpression
        {
            get
            {
                return _PasswordStrengthRegEx;
            }
        }

        public override bool RequiresQuestionAndAnswer
        {
            get { return _RequiresQuestionAndAnswer; }
        }

        public override bool RequiresUniqueEmail
        {
            get { return true; }
        }

        #endregion

        #region Methods


        

        public override MembershipUser CreateUser(string username, string password,
            string email, string passwordQuestion,
            string passwordAnswer, bool isApproved,
            object providerUserKey, out MembershipCreateStatus status)
        {

        Server srv;
        if (!string.IsNullOrEmpty(username))
        {
               
            ServerConnection cs = new ServerConnection(SQLServerName, AppContext.UserName  , AppContext.DecodePwd (AppContext.Pwd) );
            srv = new Server(cs);
             
        }
        else
        {
            srv = new Server(SQLServerName);
        }
        if (srv.Logins.Contains(username))
        {
            status = MembershipCreateStatus.DuplicateUserName;
            return null;
        }

        Login lg;
        lg = new Login(srv, username);        
        lg.LoginType = LoginType.SqlLogin;
        lg.PasswordExpirationEnabled = false;
        lg.PasswordPolicyEnforced = false;        
        try
        {
            lg.DefaultDatabase = DatabaseName_;
            if (srv.Languages.Contains("русский"))
            {
                lg.Language = "русский";
            }
            lg.Create(password, LoginCreateOptions.None);
            if (srv.Databases.Contains(DatabaseName_))
            {
                User user = new User(srv.Databases[DatabaseName_], username);
                user.Login = username;                
                
                user.DefaultSchema = _DefaultSchema;                 
                user.Create();                
            }
        }
        catch
        {
            if( srv.Logins.Contains( username ) )
            {
                srv.Logins[username].Drop();
            }
            status = MembershipCreateStatus.ProviderError;
            return null;
        }

        status = MembershipCreateStatus.Success;
        MembershipUser usr = GetNewUser(username);
        return usr;
        }
        private MembershipUser GetNewUser(string username)
        {
            MembershipUser usr = new MembershipUser("XmlMembership", username, username, string.Empty, string.Empty, string.Empty, false, false, DateTime.MinValue, DateTime.MinValue, DateTime.MinValue, DateTime.MinValue, DateTime.MinValue);
            return usr;
        }
        public override bool DeleteUser(string username, bool deleteAllRelatedData)
        {
            bool rc = false;
            Server srv;
            if (!string.IsNullOrEmpty(username))
            {
                ServerConnection cs = new ServerConnection(SQLServerName, AppContext.UserName, AppContext.DecodePwd( AppContext.Pwd));
                srv = new Server(cs);
            }
            else
            {
                srv = new Server(SQLServerName);
            }
            if (srv.Logins.Contains(username))
            {
                try
                {   
                    srv.Databases[DatabaseName_].Users[username].Drop();                    
                    srv.Logins[username].Drop();
                    rc = true;
                }
                catch
                {
                    rc = false;
                }
            }
            return rc;
         
        }

        public override MembershipUser GetUser(string username, bool userIsOnline)
        {
            int i0=0,i1=0,i2=0;
            foreach (MembershipUser  u in FindUsersByName(username,i0,i1,out i2)) 
            { 
                return u; 
            }
            return null;
        }

        public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public override string GetUserNameByEmail(string email)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public override void UpdateUser(MembershipUser user)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        
        public override bool ValidateUser(string username, string password)
        {            
            bool isOk = false;
            using (SqlConnection conn = new SqlConnection())
            {
                string strConn = string.Format("Server={0};Database={1}; User ID={2}; Password={3};", SQLServerName, DatabaseName, username, password);
                conn.ConnectionString = strConn;
                try
                {
                    conn.Open();
                    isOk = true;
                    conn.Close();
                    SqlConnection.ClearPool(conn);                    
                }                
                catch (SqlException)
                {
                }
                // Сформировать контекст безопасности 
                SecuretyContext SC= new SecuretyContext (strConn);
                AppContext.SetSC(username, password);                         
                 
            }
            return isOk;
        }

        public override bool ChangePassword(string username, string oldPassword, string newPassword)
        {
            bool isOk = false;
            // законектиться со старым паролем - если все нормально - меняем 
            if(ValidateUser (username,oldPassword))
            {

            
            }
            return isOk; 
   
        }

        public override bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPasswordAnswer)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)
        {
            MembershipUserCollection r = new MembershipUserCollection();
            User u;
            totalRecords = 0;
            try
            {
                Server srv = new Server(SQLServerName);
                Database catalog = srv.Databases[DatabaseName_];
                u=catalog.Users[usernameToMatch];
            }
            catch
            {
                return r ;
            }
            
            r.Add(GetNewUser (usernameToMatch));
            return r;

 
        }

        public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)
        {
            MembershipUserCollection r = new MembershipUserCollection();            
            totalRecords = 0;
            try
            {
                Server srv = new Server(SQLServerName);
                Database catalog = srv.Databases[DatabaseName_];
                foreach (User u in catalog.Users)
                {
                    r.Add(GetNewUser(u.Name));
                }
            
            }
            catch
            {
                return r;
            }
            
            return r;

        }

        public override int GetNumberOfUsersOnline()
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public override string GetPassword(string username, string answer)
        {
            Server srv = new Server(SQLServerName);
            Database catalog = srv.Databases[DatabaseName_];
            LoginCollection LoginColl = srv.Logins;              
                       

            foreach (User u in catalog.Users)
            {
                if (username.ToUpper () == u.Login.ToUpper ())
                {

                    return string.Empty;

                }
            }
            
            return string.Empty;
        }

        private User GetSmoUser(string Name)
        {
            try
            {
                Server srv = new Server(SQLServerName);
                Database catalog = srv.Databases[DatabaseName_];
                foreach (User u in catalog.Users)
                {
                    if(Name.ToUpper()==  u.Name.ToUpper()) return u;
                }
                return null;
            }
            catch
            {
                return null;
            }
        }

        public override string ResetPassword(string username, string answer)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public override bool UnlockUser(string userName)
        {
            throw new Exception("The method or operation is not implemented.");
        }



        #endregion

        #region Private Helper Methods
        

        #endregion
        

    }
}
